package com.bio.tests;

import com.bio.jpa.entities.*;
import com.bio.jpa.entities.File;
import com.bio.jsf.FileController;
import java.io.*;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;

@SessionScoped
@ManagedBean(name = "genBankParser")
public class GenBankParser implements Serializable {

    private String field = "";
    private String default_filtered_file_name = "file.gb";
    private StringBuilder value = new StringBuilder();
    private int type = 0;
    private Set<String> keywords = new HashSet<String>();
    private Set<String> subkeywords = new HashSet<String>();
    private Set<String> featurekeywords = new HashSet<String>();
    private Set<String> qualifierskeywords = new HashSet<String>();
    private Set<String> allkeys = new HashSet<String>();
    private String keylist[] = "LOCUS,DEFINITION,ACCESSION,VERSION,GI,DBLINK,KEYWORDS,SEGMENT,SOURCE,REFERENCE,COMMENT,FEATURES,CONTIG,ORIGIN,//".split(",");
    private String subkeylist[] = "ORGANISM,AUTHORS,CONSRTM,TITLE,JOURNAL".split(",");
    private String featurekeylist[] = "polyA_site,polyA_signal,assembly_gap,allele,attenuator,C_region,CAAT_signal,CDS,conflict,D-loop,D_segment,enhancer,exon,gene,GC_signal,iDNA,intron,J_region,LTR,mat_peptide,misc_binding,misc_difference,misc_feature,misc_recomb,misc_RNA,misc_signal,misc_structure,modified_base,mRNA,mutation,N_region,old_sequence,polyA_signal,polyA_site,precursor_RNA,prim_transcript,primer,primer_bind,promoter,protein_bind,RBS,rep_origin,repeat_region,repeat_unit,rRNA,S_region,satellite,scRNA,sig_peptide,snRNA,source,stem_loop,STS,TATA_signal,terminator,transit_peptide,transposon,tRNA,unsure,V_region,variation,-10_signal,-35_signal,3'clip,3'UTR,5'clip,5'UTR".split(",");
    private String qualifierskeylist[] = "/allele,/anticodon,/artificial_location,/bio_material,/bound_moiety,/cell_line,/cell_type,/chromosome,/citation,/clone,/clone_lib,/codon_start,/collected_by,/collection_date,/compare,/country,/cultivar,/culture_collection,/db_xref,/dev_stage,/direction,/EC_number,/ecotype,/environmental_sample,/estimated_length,/exception,/experiment,/focus,/frequency,/function,/gap_type,/gene,/gene_synonym,/germline,/haplogroup,/haplotype,/host,/identified_by,/inference,/isolate,/isolation_source,/lab_host,/lat_lon,/linkage_evidence,/locus_tag,/map,/macronuclear,/mating_type,/mobile_element_type,/mod_base,/mol_type,/ncRNA_class,/note,/number,/old_locus_tag,/operon,/organelle,/organism,/partial,/PCR_conditions,/PCR_primers,/phenotype,/pop_variant,/plasmid,/product,/protein_id,/proviral,/pseudo,/rearranged,/replace,/ribosomal_slippage,/rpt_family,/rpt_type,/rpt_unit_range,/rpt_unit_seq,/satellite,/segment,/serotype,/serovar,/sex,/specimen_voucher,/standard_name,/strain,/sub_clone,/sub_species,/sub_strain,/tag_peptide,/tissue_lib,/tissue_type,/transgenic,/translation,/transl_except,/transl_table,/trans_splicing,/variety".split(",");
    private Map<String, String> userkeywords = new HashMap<String, String>();
    private Map<String, String> usersubkeywords = new HashMap<String, String>();
    private Map<String, String> userfeaturekeywords = new HashMap<String, String>();
    private Map<String, String> userqualifierskeywords = new HashMap<String, String>();
    private Map<String, String> userallkeys = new HashMap<String, String>();
    private File current_file;
    private java.io.File filtered_file;
    private ParserFilter pf;
    private List<GenBank> genbanks = new ArrayList<GenBank>();
    private String current = null;
    private HashMap< String, List<String[]>> infoMap = new HashMap<String, List<String[]>>();

    public java.io.File getFiltered_file() {
        return filtered_file;
    }

    public void setFiltered_file(java.io.File filtered_file) {
        this.filtered_file = filtered_file;
    }

    public List<GenBank> getGenbanks() {
        return genbanks;
    }

    public void setGenbanks(List<GenBank> genbanks) {
        this.genbanks = genbanks;
    }

    public ParserFilter getPf() {
        if (pf == null) {
            pf = new ParserFilter();
        }
        return pf;
    }

    public List<String> completeQualifiers(String query) {
        List<String> suggestions = new ArrayList<String>();
        for (String p : qualifierskeylist) {
            if (p.startsWith(query)) {
                suggestions.add(p);
            }
        }
        return suggestions;
    }

    public void setPf(ParserFilter pf) {
        this.pf = pf;
    }

    public File getCurrent_file() {
        return current_file;
    }

    public void setCurrent_file(File current_file) {
        this.current_file = current_file;
    }

    public GenBankParser() {
        System.out.println("Loading GenBank Parser");
        reset();
    }

    private void reset() {
        keywords.clear();
        subkeywords.clear();
        featurekeywords.clear();
        qualifierskeywords.clear();
        allkeys.clear();
        keywords.addAll(Arrays.asList(keylist));
        subkeywords.addAll(Arrays.asList(subkeylist));
        featurekeywords.addAll(Arrays.asList(featurekeylist));
        qualifierskeywords.addAll(Arrays.asList(qualifierskeylist));
        allkeys.addAll(keywords);
        allkeys.addAll(subkeywords);
        allkeys.addAll(featurekeywords);
        allkeys.addAll(qualifierskeywords);
        allkeys.add("/");
    }

    private void loadFilter() {
        keywords.clear();
        subkeywords.clear();
        featurekeywords.clear();
        qualifierskeywords.clear();
        allkeys.clear();

        keywords.addAll(getPf().getMandatorykey());
        subkeywords.addAll(getPf().getMandatorysubkey());
        featurekeywords.addAll(getPf().getMandatoryfeaturekeys());

        keywords.addAll(getPf().getDual_kw().getTarget());
        subkeywords.addAll(getPf().getDual_skw().getTarget());
        featurekeywords.addAll(getPf().getDual_fkw().getTarget());
        qualifierskeywords.addAll(getPf().getDual_qkw().getTarget());

        allkeys.addAll(keywords);
        allkeys.addAll(subkeywords);
        allkeys.addAll(featurekeywords);
        allkeys.addAll(qualifierskeywords);
    }

    public Map<String, String> getUserallkeys() {
        return userallkeys;
    }

    public void setUserallkeys(Map<String, String> userallkeys) {
        this.userallkeys = userallkeys;
    }

    public Map<String, String> getUserfeaturekeywords() {
        return userfeaturekeywords;
    }

    public void setUserfeaturekeywords(Map<String, String> userfeaturekeywords) {
        this.userfeaturekeywords = userfeaturekeywords;
    }

    public Map<String, String> getUserkeywords() {
        return userkeywords;
    }

    public void setUserkeywords(Map<String, String> userkeywords) {
        this.userkeywords = userkeywords;
    }

    public Map<String, String> getUserqualifierskeywords() {
        return userqualifierskeywords;
    }

    public void setUserqualifierskeywords(Map<String, String> userqualifierskeywords) {
        this.userqualifierskeywords = userqualifierskeywords;
    }

    public Map<String, String> getUsersubkeywords() {
        return usersubkeywords;
    }

    public void setUsersubkeywords(Map<String, String> usersubkeywords) {
        this.usersubkeywords = usersubkeywords;
    }

    public String preProcessGB(File file) {
        type = 0;
        FileController fc = (FileController) FacesContext.getCurrentInstance().getApplication().getELResolver().
                getValue(FacesContext.getCurrentInstance().getELContext(), null, "fileController");
        java.io.File f = fc.unChunckFile(file);
        getPf().setOriginal_file(f.getAbsolutePath());
        try {
            StreamTokenizer tok = new StreamTokenizer(new FileReader(f));
            setGrama(tok);
            getPf().configure();
            while (type != StreamTokenizer.TT_EOF) {
                type = tok.nextToken();
                current = tok.sval;
                if (type == StreamTokenizer.TT_WORD) {
                    if (allkeys.contains(current)) {
//                            System.out.println(current);
                        if (keywords.contains(field) && !userkeywords.containsKey(field) && !getPf().getMandatory().contains(field)) {
                            userkeywords.put(field, field);
                            getPf().getDual_kw().getSource().add(field);
                        } else if (subkeywords.contains(field) && !usersubkeywords.containsKey(field) && !getPf().getMandatory().contains(field)) {
                            usersubkeywords.put(field, field);
                            getPf().getDual_skw().getSource().add(field);
                        } else if (featurekeywords.contains(field) && !userfeaturekeywords.containsKey(field) && !getPf().getMandatory().contains(field)) {
                            userfeaturekeywords.put(field, field);
                            getPf().getDual_fkw().getSource().add(field);
                        } else if (qualifierskeywords.contains(field) && !userqualifierskeywords.containsKey(field) && !getPf().getMandatory().contains(field)) {
                            userqualifierskeywords.put(field, field);
                            getPf().getDual_qkw().getSource().add(field);
                        }
                        field = current;
                    }
                }
            }
            getPf().getKeywords().addAll(userkeywords.keySet());
            getPf().getFeaturekeywords().addAll(userfeaturekeywords.keySet());
            getPf().getSubkeywords().addAll(usersubkeywords.keySet());
            getPf().getQualifierskeywords().addAll(userqualifierskeywords.keySet());
            getPf().configure();

        } catch (IOException ex) {
            Logger.getLogger(GenBankParser.class.getName()).log(Level.SEVERE, null, ex);
        }
        return "FilteredView";
    }

    public static void main(String[] args) throws FileNotFoundException, IOException {
        String val = "MSFQQGLSGLHGASKHLDVIGNNVANASTVGFKQGQVQFADAYA                     NSMNRSGNSPVGIGVTVANVSQAFTQGNIATTNNALDVAINGDGFFRMAASLTDQSPR                     YGRNGQFQLNKDGYLINPSMNGAYLTGYPAGTNGGDPVPLKIDTATLPATATTRVSTK                     VNLDSRKSVPTVSPFDPANPNSYSNSTGATVYDSLGNPYSLQTFYVKGAATGTPPSTT                     WSVYATLDGKTIINAPPATGPQLLGTLRFDATGALTASTGMSLNLSTLAKGGATFPGP                     IALGYAGSTQTGSAFANLAQSQDGMPPGTLSSFSIGKDGSIIGAYSNQQTRVMGQIVL                     VNFANPHGLQPIGNNLYQASEAAGSALVGTPTTGAFGALQGRAVEQSNVDLTAELVNM                     IVAQRVYQANSQTIKVQDTVLQTLVSLR";
        System.out.println(val.replaceAll("\\s+", "#"));
        System.exit(0);
        GenBankParser bp = new GenBankParser();
        List<GenBank> genbanks = bp.parse("/home/diego/Downloads/sequence.gb");
        // System.out.println(genbanks.get(0).getSequenceList().get(459));
        //System.out.println("123 actacta tcatcat".toString().replaceAll("[\\s\\d]", ""));
        System.out.println(bp.export(genbanks).getAbsolutePath());
        //String seq = "cgccgtgacgctgctgggcttgcgcatggcgcggctgctggcctttccactgttgttcct";

    }
    /*
     * Positions Contents --------- -------- 01-05 'LOCUS' 06-12 spaces 13-28
     * Locus name 29-29 space 30-40 Length of sequence, right-justified 41-41
     * space 42-43 bp 44-44 space 45-47 spaces, ss- (single-stranded), ds-
     * (double-stranded), or ms- (mixed-stranded) 48-53 NA, DNA, RNA, tRNA
     * (transfer RNA), rRNA (ribosomal RNA), mRNA (messenger RNA), uRNA (small
     * nuclear RNA). Left justified. 54-55 space 56-63 'linear' followed by two
     * spaces, or 'circular' 64-64 space 65-67 The division code (see Section
     * 3.3) 68-68 space 69-79 Date, in the form dd-MMM-yyyy (e.g., 15-MAR-1991)
     *
     */

    public StringBuilder formatForFile(GenBank gb) {
        System.out.println(subkeywords);
        System.out.println(featurekeywords);
        System.out.println(qualifierskeywords);
        StringBuilder line = new StringBuilder();
        StringBuilder doc = new StringBuilder();
        Collections.sort(gb.getFeatureList());
        for (int m = 0; m < gb.getFeatureList().size(); m++) {
            Feature feat = gb.getFeatureList().get(m);
            if (keywords.contains(feat.getName())) {
                if (!feat.getName().equalsIgnoreCase("LOCUS")) {
                    doc.append("\n");
                }
                if (feat.getName().equalsIgnoreCase("LOCUS")) {
                    doc.append(feat.getValue());
                } else if (feat.getName().equalsIgnoreCase("ORIGIN")) {
                    feat.setValue("");
                    int reads = 0;
                    int buffer = 10;
                    char[] buf = new char[buffer];
                    line.setLength(0);
                    int bytes = 0;
                    doc.append(String.format("%-12s", feat.getName()));
                    doc.append("\n");
                    doc.append(String.format("%9s", 1));
                    doc.append(" ");
                    Collections.sort(gb.getSequenceList());
                    synchronized (gb.getSequenceList()) {
                        for (int s = 0; s < gb.getSequenceList().size(); s++) {
                            Sequence sequence = gb.getSequenceList().get(s);
                            StringReader br = new StringReader(sequence.getSeq());
                            try {
                                while ((reads = br.read(buf)) != -1) {
                                    bytes += reads;
                                    if (bytes % 60 == 0) {
                                        line.append(String.valueOf(buf, 0, reads));
                                        line.append("\n");
                                        line.append(String.format("%9s", bytes + 1));
                                        line.append(" ");
                                        doc.append(line);
                                        line.setLength(0);
                                    } else {
                                        line.append(String.valueOf(buf, 0, reads));
                                        line.append(" ");
                                    }
                                }
                                doc.append(line.toString().trim());
                                line.setLength(0);
                            } catch (IOException ex) {
                                Logger.getLogger(GenBankParser.class.getName()).log(Level.SEVERE, null, ex);
                            }
                        }
                    }

                } else if (feat.getName().equalsIgnoreCase("FEATURES")) {
                    doc.append(String.format("%-12s", feat.getName()));
                    doc.append(String.format("%-9s", ""));
                    doc.append(feat.getValue());
                    line.setLength(0);
                    Collections.sort(feat.getFeatureKeyList());
                    for (int t = 0; t < feat.getFeatureKeyList().size(); t++) {
                        FeatureKey featureKey = feat.getFeatureKeyList().get(t);
                        if (featurekeywords.contains(featureKey.getName())) {
                            doc.append("\n");
                            doc.append(String.format("%-5s", " "));
                            doc.append(String.format("%-16s", featureKey.getName()));
                            if ((featureKey.getValue().length() + 22) > 79) {
                                line.setLength(0);
                                String[] words = featureKey.getValue().split(",");
                                for (int i = 0; i < words.length; i++) {
                                    String word = words[i];
                                    if (22 + line.length() + word.length() > 79) {
                                        doc.append(line.toString().trim());
                                        line.setLength(0);
                                        doc.append("\n");
                                        doc.append(String.format("%-21s", ""));
                                    }
                                    line.append(word);
                                    line.append(" ");
                                }
                                doc.append(line.toString().trim());
                            } else {
                               doc.append(String.format("%-16s", featureKey.getValue()));
                            }
                            Collections.sort(featureKey.getQualifierList());
                            for (int k = 0; k < featureKey.getQualifierList().size(); k++) {
                                Qualifier qualifier = featureKey.getQualifierList().get(k);
                                if (qualifierskeywords.contains(qualifier.getName())) {
                                    doc.append("\n");
                                    doc.append(String.format("%-21s", " "));
                                    doc.append(qualifier.getName());
                                    if (qualifier.getValue().length() > 0) {
                                        doc.append("=");
                                    }
                                    if (qualifier.getName().equalsIgnoreCase("/translation")) {
                                        doc.append(qualifier.getValue().trim().replaceAll("\\s+", "\n" + String.format("%-21s", " ")));
                                    } else if (22 + qualifier.getName().length() + qualifier.getValue().length() > 79) {
                                        line.setLength(0);
                                        boolean first_line = true;
                                        String[] words = qualifier.getValue().split(" ");
                                        for (int i = 0; i < words.length; i++) {
                                            String word = words[i];
                                            if (22 + qualifier.getName().length() + line.length() + word.length() > 79 && first_line) {
                                                doc.append(line.toString().trim());
                                                line.setLength(0);
                                                doc.append("\n");
                                                first_line = false;
                                                doc.append(String.format("%-21s", ""));
                                            } else if (21 + line.length() + word.length() > 79) {
                                                doc.append(line.toString().trim());
                                                line.setLength(0);
                                                doc.append("\n");
                                                doc.append(String.format("%-21s", ""));
                                            }
                                            line.append(word);
                                            line.append(" ");
                                        }
                                        doc.append(line.toString().trim());
                                    } else {
                                        doc.append(qualifier.getValue().trim());
                                    }
                                }
                            }
                        }
                    }
                } else {
                    doc.append(String.format("%-12s", feat.getName()));
                    if ((feat.getValue().length() + 12) > 79) {
                        line.setLength(0);
                        String[] words = feat.getValue().split(" ");
                        for (int i = 0; i < words.length; i++) {
                            String word = words[i];
                            if (12 + line.length() + word.length() > 79) {
                                doc.append(line.toString().trim());
                                line.setLength(0);
                                doc.append("\n");
                                doc.append(String.format("%-12s", ""));
                            }
                            line.append(word);
                            line.append(" ");
                        }
                        doc.append(line.toString().trim());
                    } else {
                        doc.append(feat.getValue().trim());
                    }
                }
            } else if (subkeywords.contains(feat.getName())) {
                doc.append("\n");
                doc.append("  ");
                doc.append(String.format("%-10s", feat.getName()));
                if (feat.getName().equalsIgnoreCase("ORGANISM")) {
                    if ((feat.getValue().length() + 12) > 79) {
                        line.setLength(0);
                        String[] words = feat.getValue().split(" ");
                        boolean first = true;
                        for (int i = 0; i < words.length; i++) {
                            if (words[i].contains(";") && first) {
                                doc.append(line.toString().trim());
                                doc.append("\n");
                                doc.append(String.format("%-12s", ""));
                                line.setLength(0);
                                line.append(words[i]);
                                line.append(" ");
                                first = false;
                            } else {
                                if (12 + line.length() + words[i].length() > 79) {
                                    doc.append(line.toString().trim());
                                    line.setLength(0);
                                    doc.append("\n");
                                    doc.append(String.format("%-12s", ""));
                                }
                                line.append(words[i]);
                                line.append(" ");
                            }
                        }
                        doc.append(line.toString().trim());
                    } else {
                        doc.append(feat.getValue().trim());
                    }
                } else {
                    if ((feat.getValue().length() + 12) > 79) {
                        line.setLength(0);
                        String[] words = feat.getValue().split(" ");
                        for (int i = 0; i < words.length; i++) {
                            String word = words[i];
                            if (12 + line.length() + word.length() > 79) {
                                doc.append(line.toString().trim());
                                line.setLength(0);
                                doc.append("\n");
                                doc.append(String.format("%-12s", ""));
                            }
                            line.append(word);
                            line.append(" ");
                        }
                        doc.append(line.toString().trim());
                    } else {
                        doc.append(feat.getValue().trim());
                    }
                }

            }

            // System.out.println("\n---------+---------+---------+---------+---------+---------+---------+---------");
            //System.out.println("1       10        20        30        40        50        60        70       79");
        }
        doc.append("\n//\n");
        return doc;
    }

    public java.io.File export(List<GenBank> gbs) {
        System.out.println("Exporting to file with genbanks...");
        StringBuilder sb = new StringBuilder();
        infoMap.clear();
        for (GenBank genBank : gbs) {
            sb.append(formatForFile(genBank));
        }
        filtered_file = FileController.saveToFile(sb, default_filtered_file_name, true);
        SerialUtil.Save(infoMap, default_filtered_file_name.replace(".gb", ".info"));
        infoMap.clear();
        return filtered_file;
    }

    public String analyze(GenBank gbs) {
        for (Feature f : gbs.getFeatureList()) {
            if (f.getName().equalsIgnoreCase("FEATURES")) {
                for (FeatureKey fk : f.getFeatureKeyList()) {
                    List<String[]> info = new ArrayList();
                    info.add(
                            new String[]{"Color", fk.getStatusStsId().getStsColor()});
                    info.add(
                            new String[]{"Status", fk.getStatusStsId().getStsStatus()});
                    info.add(
                            new String[]{"Name", fk.getName()});
                    infoMap.put(fk.getValue(), info);
                }
            }
        }
        SerialUtil.Save(infoMap, default_filtered_file_name.replace(".gb", ".info"));
        return "Analyze";
    }

    public java.io.File exportToFile(GenBank gbs) {
        System.out.println("Exporting to file with genbanks...");
        infoMap.clear();
        filtered_file = FileController.saveToFile(formatForFile(gbs), "./" + default_filtered_file_name, false);
        System.out.println("Saved in " + filtered_file.getAbsolutePath());
        infoMap.clear();
        return filtered_file;
    }

    public StringBuilder exportToMemory(GenBank gbs) {
        System.out.println("Exporting to String Builder with genbanks...");
        return formatForFile(gbs);
    }

    public String exportAndGetPath(GenBank gbs) {
        System.out.println("Exporting to file with genbanks...");
        StringBuilder sb = new StringBuilder();
        infoMap.clear();
        gbs.getFeatureList().size();
        sb.append(formatForFile(gbs));
        filtered_file = FileController.saveToFile(sb, default_filtered_file_name, false);
        System.out.println(filtered_file.getAbsolutePath());
        infoMap.clear();
        return filtered_file.getAbsolutePath();
    }

    public java.io.File export() {
        parse(getPf().getOriginal_file());
        StringBuilder sb = new StringBuilder();
        loadFilter();
        for (GenBank genBank : genbanks) {
            sb.append(formatForFile(genBank));
        }
        filtered_file = FileController.saveToFile(sb, default_filtered_file_name, false);
        reset();
        return filtered_file;
    }

    public String getInfo(GenBank gb) {
        System.out.println("Exporting to file with genbanks...");
        for (Feature f : gb.getFeatureList()) {
            if (f.getName().equalsIgnoreCase("FEATURES")) {
                for (FeatureKey fk : f.getFeatureKeyList()) {
                    List<String[]> info = new ArrayList();
                    info.add(
                            new String[]{"Color", fk.getStatusStsId().getStsColor()});
                    info.add(
                            new String[]{"Status", fk.getStatusStsId().getStsStatus()});
                    info.add(
                            new String[]{"Name", fk.getName()});
                    info.add(
                            new String[]{"idfeature_key", String.valueOf(fk.getIdFeatureKey())});
                    infoMap.put(fk.getValue(), info);
                }
            }
        }
        return SerialUtil.Save(infoMap, default_filtered_file_name.replace(".gb", ".info"));
    }

    public StringBuilder expandLeft(StringBuilder string, int size_to_expand) {
        StringBuilder new_sb = new StringBuilder(String.format("%-" + (size_to_expand) + "s", string.toString()));
        string.setLength(0);
        return new_sb;
    }

    public StringBuilder expandRight(StringBuilder string, int size_to_expand) {
        StringBuilder new_sb = new StringBuilder(String.format("%" + (size_to_expand) + "s", string.toString()));
        string.setLength(0);
        return new_sb;
    }

    public void setGrama(StreamTokenizer tok) {
        // recreate standard syntax table
        tok.resetSyntax();
        tok.whitespaceChars('\u0000', '\u0020');

        tok.wordChars('a', 'z');
        tok.wordChars('A', 'Z');
        tok.wordChars('\u00A0', '\u00FF');
        // tok.commentChar('/');
        tok.quoteChar('\'');
        tok.quoteChar('"');

        tok.eolIsSignificant(false);
        tok.slashSlashComments(false);
        tok.slashStarComments(false);
//tok.parseNumbers();  // this WOULD be part of the standard syntax
// Exclude from separator
        tok.wordChars('0', '9');
        tok.wordChars('.', '.');
        tok.wordChars('_', '_');
        // tok.wordChars(' ', ' ');
        tok.wordChars('-', '-');
        tok.wordChars('\'', '\'');
        tok.wordChars('@', '@');
        tok.wordChars(',', ',');
        tok.wordChars('"', '"');
        tok.wordChars(':', ':');
        tok.wordChars('/', '/');
        tok.wordChars('(', ')');
        tok.wordChars(';', ';');
        tok.wordChars('+', '+');
        tok.wordChars('[', ']');
    }

    public List<GenBank> parse(Object file) {
        genbanks.clear();
        type = 0;
        try {
            StreamTokenizer tok = null;
            String first_line = "";

            if (file instanceof String) {
                tok = new StreamTokenizer(new FileReader(file.toString()));
            } else if (file instanceof java.io.File) {
                tok = new StreamTokenizer(new FileReader(((java.io.File) file)));
            }
            FileReader fr = new FileReader(String.valueOf(file));
            BufferedReader br = new BufferedReader(fr);
            while ((first_line = br.readLine()) != null && (first_line = first_line.trim()).length() > 0) {
                System.out.println(first_line);
                break;
            }
            setGrama(tok);
// create regex to verify numeric conversion in order to avoid having
// to catch NumberFormatException errors from Double.parseDouble()
            int pos = 1;
            int seq = 0;
            int buffer = 60 * 200;
            char[] buf = new char[buffer];

            FeatureKey fk = null;
            Feature parent = null;
            Qualifier q = null;
            GenBank gb = new GenBank();

            int reads = 0;
            StringBuilder sb = new StringBuilder(buffer);
            List<Sequence> sequences = new ArrayList<Sequence>();

            while (type != StreamTokenizer.TT_EOF) {
                type = tok.nextToken();
                current = tok.sval;
                if (type == StreamTokenizer.TT_WORD) {
                    if (allkeys.contains(current) || current.startsWith("/")) {
                        seq++;
                        if (allkeys.contains(current) || current.startsWith("/")) {
                            if (value.toString().replaceAll("[^\"]", "").length() == 1) {//Check if the last content was closed
                                value.append(current);
                                value.append(" ");
                                continue;
                            }
                        }
                        if (keywords.contains(field) || subkeywords.contains(field)) {
                            if (field.equalsIgnoreCase("ORIGIN")) {
                                setGrama(tok);
                                StringReader sr = new StringReader(sb.toString());
                                while ((reads = sr.read(buf)) != -1) {
                                    sequences.add(new Sequence(String.valueOf(buf, 0, reads), pos, gb));
                                    pos = buffer + pos;
                                }
                                gb.setSequenceList(sequences);
                            }

                            if (!field.equalsIgnoreCase("//")) {
                                String content = value.toString();
                                if (field.equalsIgnoreCase("LOCUS")) {
                                    content = first_line;
                                }
                                if (fk != null) {
                                    parent.getFeatureKeyList().add(fk);
                                }
                                parent = new Feature(field, content, seq, gb);
                                if (parent.getName().equalsIgnoreCase("ORIGIN")) {
                                    parent.setValue(gb.getSequenceSize() + "");
                                }
                                gb.getFeatureList().add(parent);
                            }
                            if (current.equalsIgnoreCase("//")) {
                                if (gb.getFeatureList().size() > 1) {
                                    gb.setDefinition(gb.getFeatureList().get(1).getValue());
                                    gb.setVersion(gb.getFeatureList().get(3).getValue());
                                }
                                gb.setCreationDate(new Date());
                                genbanks.add(gb);
                                gb = new GenBank();
                            }
                        } else if (featurekeywords.contains(field)) {
                            if (fk != null) {
                                parent.getFeatureKeyList().add(fk);
                            }
                            fk = new FeatureKey(field, value.toString(), seq, parent);
                            fk.setStatusStsId(new Status(1));
                        } else if (field.startsWith("/") && !field.equalsIgnoreCase("//")) {
                            q = new Qualifier(field, value.toString(), seq, fk);
                            if (field.equalsIgnoreCase("/validation")) {
                                System.out.println(field + "=" + value.toString());
                                if (value.toString().trim().equalsIgnoreCase("\"pending\"")) {
                                    fk.setStatusStsId(new Status(2));
                                } else if (value.toString().trim().equalsIgnoreCase("\"hypothetical\"")) {
                                    fk.setStatusStsId(new Status(3));
                                } else if (value.toString().trim().equalsIgnoreCase("\"valid\"")) {
                                    fk.setStatusStsId(new Status(5));
                                } else if (value.toString().trim().equalsIgnoreCase("\"unverified\"")) {
                                    fk.setStatusStsId(new Status(1));
                                } else {
                                    fk.setStatusStsId(new Status(4));
                                }
                            }
                            fk.getQualifierList().add(q);
                        }
                        value.setLength(0);
                        field = current;
                    } else {
                        if (field.equalsIgnoreCase("ORIGIN")) {
                            value.setLength(0);
                            tok.wordChars(' ', ' ');
                            tok.eolIsSignificant(true);
                            while (!keywords.contains(current)) {
                                if (type == StreamTokenizer.TT_WORD) {
                                    //System.out.println(current.replaceAll("[\\s\\d]", ""));
                                    sb.append(current.replaceAll("[\\s\\d]", ""));
                                }
                                type = tok.nextToken();
                                current = tok.sval;
                            }
                            tok.pushBack();
                        } else {
                            value.append(current);
                            value.append(" ");
                        }
                    }
                }
            }
            br.close();
        } catch (IOException err) {
            err.printStackTrace();
        }
        System.out.println("File was parsed");
        return genbanks;
    }
}
